Matlab Object Oriented Programming: Setting and getting properties for multiple objects - oop

I have a class like so:
classdef Vehicle < handle
%Vehicle
% Vehicle superclass
properties
Is_Active % Does the vehicle exist in the simualtion world?
Speed % [Km/Hour]
end
methods
function this = Vehicle(varargin)
this.Speed = varargin{1}; % The speed of the car
this.Is_Active = true;
end
end
end
I create my Vehicle-class objects in a cell form (don't ask me why - it's a laymen's workaround for global setting):
Vehicles{1} = Vehicle(100);
Vehicles{2} = Vehicle(200);
Vehicles{3} = Vehicle(50);
Vehicles{1}.Is_Active = true;
Vehicles{2}.Is_Active = true;
Vehicles{3}.Is_Active = true;
My questions:
1. Is there a way to set all three objects' active in a single command?
2. Is there a way to get all three objects' Speed in a single command?
3. Is there a way to query which vehicles are faster than X in a single command?
Thanks
Gabriel

For the members of the same class you can use round brackets (regular array):
Vehicles(1) = Vehicle(100);
Vehicles(2) = Vehicle(200);
Vehicles(3) = Vehicle(50);
To set all objects use deal:
[Vehicles(:).Is_Active] = deal( true );
You could also initialize an array of objects in the first place.
For your questions (2) and (3) the syntax is equivalent to those of MATLAB structures:
speedArray = [Vehicles.Speed];
fasterThanX = Vehicles( speedArray > X );
Such vectorization notation is a strong point of MATLAB and is used extensively.

Related

Entities inheriting Entity.lua variables, but not its methods

I am building a game with enemies and players, all of which are set up to have various states for animation and behavior. The parent class for both is Entity.lua, from which they inherit variables and methods. However, while both enemies and players are inheriting the variables, for some reason the enemies do not inherit the methods. So, if I try to call snakey:changeState('search'), for example, it gives me an error message "Attempt to call method 'changeState' (a nil value)".
I have used the same sequence for creating entities in several games in the past and never had this problem. In fact, if I create the Player in the same way, file and location as the enemies, I receive no error messages.
Here is the code where I create the entities.
local snakey
snakey = Snakey {
platform = platform,
player1 = self.player1,
player2 = self.player2,
stateMachine = StateMachine {
['search'] = function() return SnakeySearchState(snakey) end,
['chasing'] = function() return SnakeyChasingState(snakey) end,
['idle'] = function() return SnakeyIdleState(snakey) end
}
}
-- snakey:changeState('search')
-- snakey.stateMachine:change('search', params)
table.insert(self.entities, snakey)
The two coded out lines are where I noticed the problem. The first line gives and error and the second does work, but is not satisfactory because it is a work-around.
Here is the code for Entity.lua: I don't include details of the functions for brevity, but all are working properly for when player calls them.
Entity = Class{}
function Entity:init(def)
-- position
self.x = def.x
self.y = def.y
self.gravity = 6
-- many more variables
end
function Entity:changeState(state, params)
self.stateMachine:change(state)
end
function Entity:update(dt)
self.stateMachine:update(dt)
end
function Entity:collides(entity)
-- do something
end
function Entity:onDamage()
-- do something
end
function Entity:render()
- renders sprite
end
Player code (in brief)
Player = Class{__includes = Entity}
function Player:init(def)
Entity.init(self, def)
-- more variables
end
function Player:update(dt)
Entity.update(self, dt)
end
function Player:render()
Entity.render(self)
end
And perhaps the trouble spot, one one enemy's script
Snakey = Class{__includes = Entity}
function Snakey:init(def)
Entity.init(self, def)
-- yet more variables
end
function Snakey:update(dt)
Entity.update(self, dt)
-- entity behavior (works fine, so omitted)
end
function Snakey:render()
Entity.render(self)
end
Thank you very much for your help. I'm feeling quite frustrated because this sequence has worked in the past and I would really like to know why it's not calling those Entity methods.
Adding the class library
--Copyright (c) 2010-2013 Matthias Richter
local function include_helper(to, from, seen)
if from == nil then
return to
elseif type(from) ~= 'table' then
return from
elseif seen[from] then
return seen[from]
end
seen[from] = to
for k,v in pairs(from) do
k = include_helper({}, k, seen) -- keys might also be tables
if to[k] == nil then
to[k] = include_helper({}, v, seen)
end
end
return to
end
-- deeply copies `other' into `class'. keys in `other' that are already
-- defined in `class' are omitted
local function include(class, other)
return include_helper(class, other, {})
end
-- returns a deep copy of `other'
local function clone(other)
return setmetatable(include({}, other), getmetatable(other))
end
local function new(class)
-- mixins
class = class or {} -- class can be nil
local inc = class.__includes or {}
if getmetatable(inc) then inc = {inc} end
for _, other in ipairs(inc) do
if type(other) == "string" then
other = _G[other]
end
include(class, other)
end
-- class implementation
class.__index = class
class.init = class.init or class[1] or function() end
class.include = class.include or include
class.clone = class.clone or clone
-- constructor call
return setmetatable(class, {__call = function(c, ...)
local o = setmetatable({}, c)
o:init(...)
return o
end})
end
-- interface for cross class-system compatibility (see https://github.com/bartbes/Class-Commons).
if class_commons ~= false and not common then
common = {}
function common.class(name, prototype, parent)
return new{__includes = {prototype, parent}}
end
function common.instance(class, ...)
return class(...)
end
end
-- the module
return setmetatable({new = new, include = include, clone = clone},
{__call = function(_,...) return new(...) end})
It turns out that sequence matters. In trying to create the minimum reproducible code I could not reproduce the error. After some searching (and a little frustration), I noticed that in Dependencies.lua I was requiring the enemies BEFORE Entity.lua, but Player.lua was required after. I would have thought this wouldn't matter, since everything was imported into the program on frame 1 and I was creating entities on something like frame 1000, but alas. Anyway, problem solved! Always require parent classes before child classes... Lesson learned. :)

Question about when to use lua colon syntax

local Public = {}
function Public.new(ent)
local State = {}
function State:update(player)
ent:setLinearVelocity(0,0)
end
function State:start(player)
ent.fixedRotation = true
self.attackTimer = _G.m.addTimer(200, function()
ent:setState('attacking', player)
end)
end
function State:exit(player)
ent.fixedRotation = false
timer.cancel(self.attackTimer)
end
return State
end
return Public
I'm using a linter and its complaining that I'm using the colon unnecessarily for my update and exit methods. The reason I do this is to keep all my methods uniform. Sometimes I need self and sometimes I don't.
But in general is there any advantage to using colon on these at all? It seems like if i have something like State:start then I could just reference State directly. I could do State.attackTimer vs self.attackTimer..
Why would you ever really need the colon? If you have access to the table that holds the method then you have access to self.. right?
The : syntax is a great tool when you are making a class using a table and a metatable.
Your code above, rather then creating a class, creates an encapsulated set of functions. which have access to State as an upvalue.
I will use this class from Lua Users - SimpleLuaClasses as an example:
Account = {}
Account.__index = Account
function Account:create(balance)
local acnt = {} -- our new object
setmetatable(acnt,Account) -- make Account handle lookup
acnt.balance = balance -- initialize our object
return acnt
end
function Account:withdraw(amount)
self.balance = self.balance - amount
end
-- create and use an Account
acc = Account:create(1000)
acc:withdraw(100)
Here we have an instance(acc) of the Account class. To adjust or modify the values in this specific instance of Account we can not refer to Account.balance inside of Account:withdraw. We need a reference to the table where the data is stored, and that is where passing that table using : comes in.
acc:withdraw(100) is just syntactic sugar for acc.withdraw(acc, 100) passing in our table as the first param self. When you define Account:withdraw(amount) there is an implicate first variable self the definition could be written as Account.withdraw(self, amount)

OOP in Lua - Creating a class?

I'm aware there are a few questions about implementing OOP in Lua on this site, however, this one is a bit different (at least compared to what I found).
I'm trying to create a class called "human", and make it so objects created with the "new" constructor of "human", inherit everything inside human except it's constructor. However, I also don't want to be able to use methods inside of human, on human. So whatever's inside the human class, is only passed to created objects. Here's an example:
-- "Human" class
human = {}
function human.new(name)
local new = {} -- New object
-- Metatable associated with the new object
local newMeta =
{
__index = function(t, k)
local v = human[k] -- Get the value from human
print("Key: ", k)
if type(v) == "function" then -- Takes care of methods
return function(_, ...)
return v(new, ...)
end
else
return v -- Otherwise return the value as it is
end
end
}
-- Defaults
new.Name = name
new.Age = 1
return setmetatable(new, newMeta)
end
-- Methods
function human:printName()
print(self.Name)
end
function human:setAge(new)
self.Age = new
end
-- Create new human called "bob"
-- This works as expected
local bob = human.new("Bob")
print(bob.Name) -- prints 'Bob'
bob:printName() -- prints 'Bob'
bob:setAge(10) -- sets the age to 10
print(bob.Age) -- prints '10'
-- But I don't want something like this allowed:
local other = bob.new("Mike") -- I don't want the constructor passed
-- I'd also like to prevent this from being allowed, for "human" is a class, not an object.
human:printName()
So creating the object with human.new("Bob") works fine, but it also passes the constructor, and I can still use the object methods on the class. I'm very new to the concept of OOP, so I'm sorry if this was a horrible question. But if anyone could help, I'd appreciate that.
I have run into the same issue before. You need two tables. One for object methods and one for class methods. Set the metatable of constructed objects to the object method table. For example:
local Class = {}
local Object = {}
Object.__index = Object
function Class.new()
return setmetatable({}, Object)
end
setmetatable(Class, {__call = Class.new})
function Object.do()
...
end
return Class
And use it
Class = require('Class')
local obj = Class.new() -- this is valid
obj.do() -- this is valid
obj.new() -- this is invalid
Class.do() -- this is invalid

Matlab's arrayfun for uniform output of class objects

I need to build an array of objects of class ID using arrayfun:
% ID.m
classdef ID < handle
properties
id
end
methods
function obj = ID(id)
obj.id = id;
end
end
end
But get an error:
>> ids = 1:5;
>> s = arrayfun(#(id) ID(id), ids)
??? Error using ==> arrayfun
ID output type is not currently implemented.
I can build it alternatively in a loop:
s = [];
for k = 1 : length(ids)
s = cat(1, s, ID(ids(k)));
end
but what is wrong with this usage of arrayfun?
Edit (clarification of the question): The question is not how to workaround the problem (there are several solutions), but why the simple syntax s = arrayfun(#(id) ID(id), ids); doesn't work. Thanks.
Perhaps the easiest is to use cellfun, or force arrayfun to return a cell array by setting the 'UniformOutput' option. Then you can convert this cell array to an array of obects (same as using cat above).
s = arrayfun(#(x) ID(x), ids, 'UniformOutput', false);
s = [s{:}];
You are asking arrayfun to do something it isn't built to do.
The output from arrayfun must be:
scalar values (numeric, logical, character, or structure) or cell
arrays.
Objects don't count as any of the scalar types, which is why the "workarounds" all involve using a cell array as the output. One thing to try is using cell2mat to convert the output to your desired form; it can be done in one line. (I haven't tested it though.)
s = cell2mat(arrayfun(#(id) ID(id), ids,'UniformOutput',false));
This is how I would create an array of objects:
s = ID.empty(0,5);
for i=5:-1:1
s(i) = ID(i);
end
It is always a good idea to provide a "default constructor" with no arguments, or at least use default values:
classdef ID < handle
properties
id
end
methods
function obj = ID(id)
if nargin<1, id = 0; end
obj.id = id;
end
end
end

Matlab Object Oriented composition, aggregation

i'm writing my first MATLAB O-O application and i'm confused about the implementation of compositions, aggregations and relationships in general.
My question is: how to implement an aggregation or an association one-to-many in matlab? Where i can take some examples?
Moreover, i'm using ArgoUml to design my application, is there any plugin to automatic code generation in matlab?
Thanks in advance
Here is a quick example of class association. The scenario consists of a course that can have many students enrolled:
Student.m
classdef Student < handle
properties
name
end
methods
function obj = Student(name)
if nargin > 0
obj.name = name;
end
end
function delete(obj)
fprintf('-- Student Destructor: %s\n',obj.name);
end
end
end
Course.m
classdef Course < handle
properties
name %# course name
std %# cell array of students
end
properties(Access = private)
lastIdx = 1;
end
methods
function obj = Course(name, capacity)
obj.name = name;
obj.std = cell(capacity,1);
end
function addStudent(obj, std)
if obj.lastIdx > numel(obj.std)
fprintf(2, 'Sorry, class is full\n');
return
end
obj.std{obj.lastIdx} = std;
obj.lastIdx = obj.lastIdx + 1;
end
function printClassRoster(obj)
fprintf('Course Name = %s\n', obj.name);
fprintf('Enrolled = %d, Capacity = %d\n', ...
obj.lastIdx-1, length(obj.std));
for i=1:obj.lastIdx-1
fprintf('ID = %d, Name = %s\n', i, obj.std{i}.name);
end
end
end
end
And here is a code to test the above classes:
c = Course('CS101', 3);
for i=1:4
name = sprintf('amro%d',i);
fprintf('Adding student: %s\n', name)
c.addStudent( Student(name) )
end
fprintf('\nClass Roster:\n=============\n')
c.printClassRoster()
fprintf('\nCleaning up:\n')
clear c
The output:
Adding student: amro1
Adding student: amro2
Adding student: amro3
Adding student: amro4
Sorry, class is full
-- Student Destructor: amro4
Class Roster:
=============
Course Name = CS101
Enrolled = 3, Capacity = 3
ID = 1, Name = amro1
ID = 2, Name = amro2
ID = 3, Name = amro3
Cleaning up:
-- Student Destructor: amro1
-- Student Destructor: amro2
-- Student Destructor: amro3
You may have a look at Object-Oriented Programming in MATLAB and in the documentation refer to Object-Oriented Programming.
I suggest to have a closer look Value or Handle Class — Which to Use
. To make it short, handle classes let you pass references around whereas value classes are always a copy of the original object.
I'd be surprised to find a plugin for ArgoUml, as MATLAB is mainly used by engineers and not software developers.