2

I am looking at Should I use multiple classes for game? - Robert Pitt's answer.

interface Weapons {

    public function Fire();

}

class Colt implements Weapons {

    function Fire() {
        echo 'Fire!';
    }

}

abstract class Human implements Colt
{

}

class Sniper extends Human
{
    public function __construct()
    {

    }



}

On the "Human" am I perhaps to implement the "Weapons" rather then Colt, and then on the "Sniper" initialize the Right weapon class?

class Sniper extends Human
{
public $weapon;

    public function __construct($weapon)
    {
    $this->weapon = new $weapon;  
    }


$this->weapon->fire();


}

Or something like that? I am confused of how it works..

EXAMPLE 1

class A {
public $class;

__construct() {
$this->class = new $class;
}

hello() {
$this->class->hello();
}
}

class B {
public function hello() {
echo 'hi';
}
}
Community
  • 1
  • 1
John
  • 2,900
  • 8
  • 36
  • 65
  • class Human should `extend`, not `implement` the class Colt. Because it's not interface – kravemir Nov 29 '11 at 15:16
  • 1
    It's really up to you. If you were working for a company with its own list of best practises, then you'de be asking and reading documents. But since it's your project, go for it. The best way to learn is by making mistakes. – Frank Nov 29 '11 at 15:16

3 Answers3

5

It's up to you, how will you design your classes.

If I would be a game programmer, I'd probably use something like (it's a working minigame!)

<?php
class Fight {
     public $weapon;
     public $name;
     public function __construct($weapon, $name)
     {
        $this->name = $name;
        $this->weapon = new $weapon;
     }
     public function fire($person) {
         $this->weapon->fire($person);
     }
     public function changeWeapon($weapon) {
        $this->weapon = new $weapon;
     }
}

class Sniper extends Fight {   }
class Terrorist extends Fight {   }

class MauserSniper {
     function fire($person) {
         echo "Firing $person->name! Miss! Your rifle is damaged<br />";
     }
}

class AK47 {
     function fire($person) {
         echo "Firing $person->name! Hit with AK47!<br />";
     }
}


class SteyrSSG {
     function fire($person) {
         echo "Firing $person->name! Hit!<br />";
     }
}

$sniper1 = new Sniper("MauserSniper", "Martin");
$sniper2 = new Sniper("SteyrSSG", "Daniel");
$terrorist = new Terrorist("AK47", "Mike");
$sniper1->fire($sniper2); //we'll miss this one.
$sniper1->changeWeapon("SteyrSSG");
$sniper1->fire($sniper2); //hit!
$terrorist->fire($sniper1);

demo

Martin.
  • 10,494
  • 3
  • 42
  • 68
  • Thanks for an good example, but I am still unsure - How about IF I don't know what "Race" (Human, Troll, etc) is. But I need to pull that from a database, extend to a variable, doesn't work :s I guess this works better, with like NPC's (Monsters, rat) and not the "User" himself – John Nov 29 '11 at 15:24
  • Really thanks for your help so far! Its working good, but I guess, I am still thinking of how I can Extend even more things, For example, If I had a "Car" class, I would like to extend that as well, but I guess I can't extend to more then one class? – John Nov 29 '11 at 15:37
  • I think the problem is that I don't understand how I get extend a "dynamic" class, or something like that.. Aren't a pattern for it? Sniper could extend a Human, but also a Troll – John Nov 29 '11 at 15:41
  • @John: No, unfortunatelly you can't. but you can use car in fight, or not? – Martin. Nov 29 '11 at 15:41
  • @John: There are some workaround, but I don't think you'd need it. What is your suppose? – Martin. Nov 29 '11 at 15:42
  • Well - I am just relating to the question above that I refered to, that they have different "Races" Humans, etc. And then the class extend to a race, But I would like the class to be able to extend to another race, if so like, etc sniper could be the "Human" and "Troll" race. - But as I pull the data from a database, I can't know which "Race" the user really is. – John Nov 29 '11 at 15:45
  • @John: In that case `extends` isn't a good choice for you. Rather define property(ies) – Martin. Nov 29 '11 at 15:49
  • I am thinking about If I would use to extend like "Player" abstract class, and then use properties, etc? This way I can reuse my classes for NPCS and the player, does it seem like a good approach? – John Nov 29 '11 at 15:50
  • @John: exactly, it is. And you can create class `Player extends Fight` – Martin. Nov 29 '11 at 15:51
  • You need to remember that properties arent classes. The race (Human, troll, elf, goblin), class(sniper, warrior, medic, mage), nationality (Arkadian, Geominian, American, European), team (Team Red, Team Blue) are properties of it. The property itself could be another object. For example, the Troll Race could be a class that you set as a property of the "Player" class. As such, the weapon he carries is another property, not an extension of the Player's class. – Mathieu Dumoulin Nov 29 '11 at 15:52
  • Thanks for your help, very appreciated, thanks for your effort. – John Nov 29 '11 at 15:52
  • @MathieuDumoulin: I didn't mean that he shouldn't use a class, but that he should create a new instance of class INTO that property – Martin. Nov 29 '11 at 15:54
  • @Martin: don't worry, i'm just pitching my grain of salt, not saying that your code is bad, just making a note not to forget what classes, properties, events and interfaces are for. I wrote an answer below but i think it wasnt really seen since i was late (not that i want the credit of the solution, just want to make sure all options are taken into account) – Mathieu Dumoulin Nov 29 '11 at 15:55
  • No, I've read it and took it under account as well, Thanks @MathieuDumoulin – John Nov 29 '11 at 15:57
5

On my side i would instead use these classes:

Interface iWeapon {}
Interface iAttacker {}
Interface iAttackable {}

Class Human Implements iAttacker, iAttackable {}
Class RangedWeapon Implements iWeapon {}
Class Colt extends RangedWeapon {}
Class M4AA extends RangedWeapon {}
Class Sniper extends RangedWeapon {}
Class Shotgun extends RangedWeapon {}

Let me explain them now:

iWeapon

Describes a weapon, the different getters, setters and a few actions such as DoDamage() or GetRandomAttackDamage(). Its as you wish. This interface allows you to define a weapon'S basics. You could apply this to the Weapon class or any other class that derives it, but i'd keep it to at least one basic class. The goal of the interface is to force all weapons to addopt the same behavior, it has attack damage, range, maybe charges? (Ammo)

iAttacker / iAttackable

Describes something that can attack or be attacked. These interfaces will usually provide functions that determine the ability to attack (is it stunned, immobilized, disabled?) or be attacked (invisible, invincible?) and provide functions to attack the other implementation. Humans or any other creature will implement these to say, HEY, i CAN attack AND be attacked. This interface would also provide getters and setters to control the weapons these creatures carry, maybe armors to prevent damage to them?

About interfaces

Remember always that classes represent something RELATIVELY concrete. If you are naming your class "Attacker" or "Target" you might be missing the point of a class. A class and object representing something tangible. In the other way around Interfaces represent actions or roles that classes may take. They only specify what one can do, they don't provide the implementation per se, they tell what that object will implement and thus DECLARE what they can do.

Hope this helps :)


Regarding the correct implementation of properties here is what i suggest:

class Player implements iAttacker, iAttackable {
    protected $playerClass;
    protected $race;
    protected $weapon;
    protected $armor;

    public function setClass(playerClass $class){
         $this->playerClass = $class;
    }
    public function getClass(){
         return $this->playerClass;
    }

    public function setRace(race $race){
         $this->race = $race;
    }
    public function getRace(){
         return $this->race;
    }

    public function setWeapon(damagingGear $weapon){
         $this->weapon = $weapon;
    }
    public function getWeapon(){
         return $this->weapon;
    }

    public function setArmor(protectiveGear $armor){
         $this->armor = $armor;
    }
    public function getArmor(){
         return $this->armor;
    }

    public function attack(iAttackable $target){

        //Check we can attack
        if(!$this->canAttack()){ //Check we are not immobilized or disabled
            throw new CannotAttackException($this->getNonAttackingReason());
        }elseif(!$this->weapon->canFire()){
            throw new CannotAttackException($this->weapon->getNonFireableReason());
        }

        //We can attack, roll the damage
        if($target->isAttackable()){
            $target->sufferDamage($this->weapon->rollDamage()+$this->race->getRangedDamageBonus());
        }else{
            thrown new CannotBeAttackedException($target->getNonAttackableReason());
        }
    }

}
Mathieu Dumoulin
  • 12,126
  • 7
  • 43
  • 71
  • What is "RangedWeapon" suppose to contain ? =) – John Nov 29 '11 at 16:04
  • Basic implementation of what a ranged weapon can do, such as what is described in the interface. Then each other weapon can but shouldnt necessarily extend the RangedWeapon. At this point its a matter of taste, do you want to have only "Weapon", "RangedWeapon/MeleeWeapon"? Its a very large topic :) – Mathieu Dumoulin Nov 29 '11 at 16:11
  • Yeah, I'll stick to "rangedweapon, meleeweapon" for now.. I was thinking about properties, If I a declare a class in a class, doesn't it mean, i need to set a method in my class to execute it? class a sets a var to a object then in class b a method called hello() Now I need to set a "hello" method and then put like var->func() Right? (Updated my questions to show, what I mean) – John Nov 29 '11 at 16:37
  • Look at what i added, it took me some time to make that out, but i think this should lead you in what i believe is the correct direction... – Mathieu Dumoulin Nov 29 '11 at 16:58
2

I would avoid having the Human class implement anything to do with the Weapons. Implementations define which methods a class must define, but don't deal with properties of the class.

Object interfaces allow you to create code which specifies which methods a class must implement, without having to define how these methods are handled. (PHP Documentation: Object Interfaces)

Class Human {}

Class Sniper extends Human{
 public $weapon
}

Interface Weapons {
  public function fire() 
}

Class Colt implements Weapons {}
Class Bazooka implements Weapons {}

Thus a Sniper is a Human (but with a $weapon property), and a Colt, Bazooka etc all implement the Weapons interface (forcing them to define a fire() function.

nageeb
  • 2,002
  • 1
  • 13
  • 25
  • `Class Human {} Class Sniper extends Human{ public $weapon }` I don't like this. I think that $weapon is everyone's property and therefore should be in human's class – Martin. Nov 29 '11 at 15:30
  • That may be, and ignoring the political implications of such a statement :), I was addressing the Implementation, not the property inheritance. If ALL your humans have a weapon, then by all means, declare it in the parent class. – nageeb Dec 01 '11 at 03:12
  • Now we know what 'FIGHTFIGHTFIGHT' in GTA Vice City does.. =) – Debopam Parua Dec 28 '18 at 05:45