среда, 26 января 2011 г.

Урок 12. Столкновения со стенами

Мне так кажется, что предложений по урокам можно скоро не ждать, так что я пока что напишу ещё один урок. Из названия урока можно понять, что в нашем примере будет бегать человек и биться головой об стены) Так оно, в общем-то, и есть:





Сразу скажу, что это не самый лучший вариант проверки столкновений, но встроенная функция – есть встроенная функция. Так что прошу любить и комментировать. Надеюсь, что Вы уже привыкли работать с классами, потому что в последующих уроках они также будут присутствовать. Открываем новый документ as3, подсоединяем класс game, сохраняем. Создаём класс game и пишем код:
package {
 import flash.display.Sprite;
 public class game extends Sprite {
   public var Man, Map;
   public var stgWidth:Number=500;
   public var stgHeight:Number=400;
   public var general_container;
  public function game() {
   general_container=new Sprite();
   stage.addChildAt(general_container, 0);
   
   Map=new map();
   general_container.addChildAt(Map,0);
   
   Man=new man(this);
  }
 }
}

Так, лучше сейчас всё нарисовать, чтобы потом не отвлекаться. Рисуем кружок или квадратик, короче всё что хотите, только стандартной формы, чтобы маркеры было удобно вешать. Выделяем то, что Вы нарисовали, нажимаем F8 и называем man. Теперь заходим в man и там выделяем картинку, (ту, что Вы нарисовали) жмём f8 и называем это man_image. Создаём 4 маркера, 1ый называем top_marker и размещаем его вверху, 2ой называем bottom_marker и размещаем внизу и т.д. Здесь всё нужно экспортировать в as. Рисуем стену ( квадратик). Называем wall (стена) *Здесь всё нужно экспортировать в as *). И, наконец составляем карту из этих стен. Потом, выделяем все стены в нашей карте и называем это map. Так, нам осталось всего ничего – написать класс man.
Код ходьбы будет такой же, как и в вертолёте. Только мы добавим ещё функцию проверки столкновений:

private function check_hit(){
var currentWall;
 var speedX=Math.cos(this.man_image.rotation*radians)*Speed;
 var speedY=Math.sin(this.man_image.rotation*radians)*Speed;
 for(var i:int=0;i<game.Map.numChildren;i++){
  currentWall=game.Map.getChildAt(i);
  if(this.top_marker.hitTestObject(currentWall)){
   if(speedY<0){
    Speed*=-1;
   }  
  }
  else if(this.bottom_marker.hitTestObject(currentWall)){
   if(speedY>0){
    Speed*=-1;
   }
  }
  else if(this.left_marker.hitTestObject(currentWall)){
   if(speedX<0){
    Speed*=-1;
   }
  }
  else if(this.right_marker.hitTestObject(currentWall)){
   if(speedX>0){
    Speed*=-1;
   }
  }
 }
}

Сразу скажу, что это очень приблизительная проверка. Здесь нет отражения угла, да и сам hitTestObject очень не точный. Если Вам нужно точное определение столкновений, то забудьте про hitTestObject и открывайте учебник по геометрии. Ну, а про сам алгоритм: перебираем все стены и проверяем столкновение с учётом направления (с какой стороной мяч столкнулся со стеной). Можно, конечно написать свою проверку, но это довольно таки не просто. Вот весь код класса man:
package {
 import flash.display.MovieClip;
 import flash.events.*;
 import flash.ui.Keyboard;
 public class man extends MovieClip {
  public var game;
  private var radians:Number=Math.PI/180;

  private var up,down,left,right:Boolean;
  public var Speed,rotationSpeed:Number;
  private var moveSpeed,friction,maxSpeed,rotatSpeed:Number;

  public function man(Game){
   game=Game;
   this.x=game.stgWidth/2;
   this.y=game.stgHeight/2;
   Speed=0;
   rotationSpeed=0;
   maxSpeed=10;
   friction=0.94;
   moveSpeed=0.5;
   rotatSpeed=1;
   
   top_marker.visible=false;
   bottom_marker.visible=false;
   left_marker.visible=false;
   right_marker.visible=false;
   
   game.stage.addEventListener(KeyboardEvent.KEY_DOWN,key_down);
   game.stage.addEventListener(KeyboardEvent.KEY_UP,key_up);
   this.addEventListener(Event.ENTER_FRAME,move_player);
   
   game.general_container.addChildAt(this,1);
  }  
  private function key_down(e:KeyboardEvent) {
   if (e.keyCode==Keyboard.UP||e.keyCode==87) {
    up=true;
   }
   if (e.keyCode==Keyboard.LEFT||e.keyCode==65) {
    left=true;
   }
   if (e.keyCode==Keyboard.RIGHT||e.keyCode==68) {
    right=true;
   }
   if (e.keyCode==Keyboard.DOWN||e.keyCode==83) {
    down=true;
   }
  }
  private function key_up(e:KeyboardEvent) {
   if (e.keyCode==Keyboard.UP||e.keyCode==87) {
    up=false;
   }
   if (e.keyCode==Keyboard.LEFT||e.keyCode==65) {
    left=false;
   }
   if (e.keyCode==Keyboard.RIGHT||e.keyCode==68) {
    right=false;
   }
   if (e.keyCode==Keyboard.DOWN||e.keyCode==83) {
    down=false;
   }
  }
  private function move_player(e:Event) {
   if (maxSpeed>=Math.abs(Speed)) {
    if (right==true) {
     rotationSpeed+=rotatSpeed;
    }
    if (up==true) {
     Speed+=moveSpeed;
    }
    if (left==true) {
     rotationSpeed-=rotatSpeed;
    }
    if (down==true) {
     Speed-=moveSpeed;
    }
   }
   else{
    Speed=maxSpeed*(Speed/Math.abs(Speed));
   }
   check_hit();
   update_coordinats();   
  }
  private function check_hit(){
   var currentWall;
   var speedX=Math.cos(this.man_image.rotation*radians)*Speed;
   var speedY=Math.sin(this.man_image.rotation*radians)*Speed;
   for(var i:int=0;i<game.Map.numChildren;i++){
    currentWall=game.Map.getChildAt(i);
    if(this.top_marker.hitTestObject(currentWall)){
     if(speedY<0){
      Speed*=-1;
     }  
    }
    else if(this.bottom_marker.hitTestObject(currentWall)){
     if(speedY>0){
      Speed*=-1;
     }
    }
    else if(this.left_marker.hitTestObject(currentWall)){
     if(speedX<0){
      Speed*=-1;
     }
    }
    else if(this.right_marker.hitTestObject(currentWall)){
     if(speedX>0){
      Speed*=-1;
     }
    }
   }
  }
  private function update_coordinats() {
   this.man_image.rotation+=rotationSpeed;   
   
   this.x+=Math.cos(this.man_image.rotation*radians)*Speed;
   this.y+=Math.sin(this.man_image.rotation*radians)*Speed;
   rotationSpeed-=rotationSpeed*0.1;
   Speed*=friction;   
  }
 }
} 
Более подробно про столкновения можно узнать здесь.
Надеюсь, что эта информация была для Вас полезной. Комментируйте, оставляйте идеи уроков и удачи Вам! Исходник и good bye)

6 комментариев:

  1. Посмотри на цифры в коде после цифры 99

    ОтветитьУдалить
  2. Не цифры,а номера строк после 99 :)

    ОтветитьУдалить
  3. Решил коротко.
    Подскажи, как ты создавал маркеры top_marker итд.?
    Смотрел даже исходник, не понял.
    создал символ marker , поместил в символ man 4 его экземпляра, а как экземпляры то обозвать?
    смотрел в исходнике, они называются все, как символ marker. Объясни пожалуйста.

    ОтветитьУдалить
  4. Тут нужно понимать разницу между именем и классом. marker - это класс, а top_marker - это имя конкретного экземпляра класса. Чтобы изменить имя нужно выделить мувиклип, в окне properties будет поле оно и отвечает за имя.

    ОтветитьУдалить
  5. А можно увидеть урок, по созданию строки загрузки перед началом приложения?

    ОтветитьУдалить